from django_redis import get_redis_connection
from rest_framework import serializers

from oauth.models import OAuthQQUser
from users.models import User
from django.conf import settings
from itsdangerous import TimedJSONWebSignatureSerializer as TJS



# 0根据要验证的数据,确定序反列化器继承自谁,处理的数据来自两个模型类,所以继承Serializer
# 0,下面是基本验证
class OAuthQQSerializer(serializers.Serializer):
    mobile = serializers.RegexField(regex='1[3-8]\d{9}', max_length=11)     # RegexField字段,可以直接使用正则 ,
    password = serializers.CharField(max_length=20, min_length=8, write_only=True)
    sms_code = serializers.CharField(max_length=6, min_length=6, write_only=True)
    access_token = serializers.CharField(write_only=True)




    # 1具体验证
    def validate(self, attrs):
        # 2短信验证码验证 ,之前写过,直接沾了过来,
        # 3从缓存中取出短信
        conn = get_redis_connection('verify')
        sms_code_real = conn.get('sms_code_%s' % attrs['mobile'])
        # 4获取不到短信
        if not sms_code_real:
            raise serializers.ValidationError('短信失效')

        if attrs['sms_code'] != sms_code_real.decode():
            raise serializers.ValidationError('短信不一致')






        # 5access_token解密验证,他是一个加密后的openid 值 ,在这里将他解密,解密对象与加密对象生成的值需要一致
        # 6在manager 中指定了配置文件就是dev ,所以可以直接用settings找到各种配置,
        tjs = TJS(settings.SECRET_KEY, 300)
        # 7一旦解密失败的话,就会抛出异常,所以可以捕获异常,判断此值是否有效,如果是伪造的就会出错,
        try:
            data = tjs.loads(attrs['access_token'])   # 7attrs直接使用,不用导入 ,
        except:
            raise serializers.ValidationError('错误的access_token值')

        openid = data.get('openid', None) # 8如果解密正常的话,取值;给了一个默认值是怕过了有效期值清空
        # 9判断是否失效
        if not openid:
            raise serializers.ValidationError('access_token值失效')

        # 10添加openeid到attrs ,原来的attrs有access_token,没有openid
        attrs['openid'] = openid







        # 11用户验证
        #  12用户查询不到,模型类用的原来的用户模型类,
        try:
            user = User.objects.get(mobile=attrs['mobile'])
        except:
            return attrs  # 12没有user对象的话直接返回attrs ,因为抛出异常的话,不会在执行之下的,(在create下创建新用户,接下12)
            # pass 也行,道理一样,
        # 13用户查询到  校验密码(模型类下,提供的校验密码的方法)
        if user.check_password(attrs['password']):
            # 14添加user到attrs  ,用户和openid需要绑定,所以将用户添加进attrs
            attrs['user'] = user

        return attrs





    # 14 对传来的数据进行新增,保存进数据库,
    def create(self, validated_data):
        # 绑定操作  创建出OAuthQQUser模型类的对象user
        print(validated_data)
        # 12用户查询,查询不到,走下面的创建 ,
        user = validated_data.get('user', None)

        if not user:
            # 12user是none值说明用不存在
            # 12创建新用户,注意create_user 是模型类的管理器方法,可去模型类文档查看如何使用 ,User用的用户模型类,(从users子应用导入)
            # 12如此便写进了数据库 ,
            user = User.objects.create_user(username=validated_data['mobile'], password=validated_data['password'],
                                            mobile=validated_data['mobile'])

        # 15绑定user和openid ,如是绑定,create 是数据库的增删改查方法,新增使用create 写入 ,
        OAuthQQUser.objects.create(user=user, openid=validated_data['openid'])

        # jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
        # jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
        #
        # payload = jwt_payload_handler(user)
        # token = jwt_encode_handler(payload)
        # user.token = token
        return user


